package com.kcwl.idea.plugins.gateway;

import javax.swing.*;
import javax.swing.tree.*;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.kcwl.idea.plugins.base.checkboxtree.CheckBoxNodeData;
import com.kcwl.idea.plugins.base.checkboxtree.CheckBoxNodeEditor;
import com.kcwl.idea.plugins.base.checkboxtree.CheckBoxNodeRenderer;
import com.kcwl.idea.plugins.gateway.config.KcGatewaySettings;
import com.kcwl.idea.plugins.gateway.handler.*;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.ui.DialogWrapper;
import com.kcwl.idea.plugins.gateway.handler.Menu;
import lombok.Getter;
import org.jetbrains.annotations.NotNull;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.util.*;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Rap2配置菜单界面
 */
@Getter
public class GatewayEditForm extends DialogWrapper {

    private JPanel panel;
    private JComboBox<KcService> serviceComboBox;
    private JComboBox<RouteType> routeTypeComboBox;
    private JTextField apiDescField;
    private JTextField authorField;
    private JTextField apiPathField;
    private JPanel products;
    private JPanel resourceTreePanel;
    private List<ApiInfo> apiInfos;
    private List<KcProduct> productList;
    private List<KcService> serviceList;
    private AnActionEvent actionEvent;

    private KcService currentKcService;

    private Map<String, List<Menu>> productMenu;
    /**
     * 是否刷新缓存
     */
    private boolean flushCache;

    public GatewayEditForm(AnActionEvent e) {
        super(true); // use current window as parent
        //判断是否配置了网关
        actionEvent = e;
        setTitle("API-新增/编辑");
        init();
        //数据回填
        initData();

    }



    public void initData() {
        //接口地址回填
        String apiPath = ControllerInfoUtil.getApiPath(actionEvent);

        String apiSummary = ControllerInfoUtil.getApiSummary(actionEvent);

        apiPathField.setText(apiPath);

        KcGatewaySettings settings = KcGatewaySettings.getInstance();

        //获取已存在的接口
        ApiInfo apiInfo = null;
        if (CollUtil.isNotEmpty(apiInfos)) {
            apiInfo = apiInfos.get(0);
        }
        for (KcService kcService : serviceList) {
            serviceComboBox.addItem(kcService);
            if (apiInfo != null) {
                if (kcService.getServiceName().equals(apiInfo.getServiceName())) {
                    serviceComboBox.setSelectedItem(kcService);
                }
            } else {
                if (currentKcService != null && kcService.getId().equals(currentKcService.getId())) {
                    serviceComboBox.setSelectedItem(kcService);
                }
            }
        }

        for (RouteType routeType : RouteType.buildList()) {
            routeTypeComboBox.addItem(routeType);
            if (apiInfo != null) {
                if (routeType.getId().equals(apiInfo.getRouteType())) {
                    routeTypeComboBox.setSelectedItem(routeType);
                }
            }
        }
        apiDescField.setText(apiSummary);
        if (apiInfo != null) {
            authorField.setText(apiInfo.getAuthor());
            apiDescField.setText(apiInfo.getApiDesc());
        } else {
            authorField.setText(settings.getAuthor());
        }

    }

    @Override
    protected JComponent createCenterPanel() {
        // 设置对话框的高度和宽度
        this.panel.setPreferredSize(new Dimension(600, 400));
        return this.panel;
    }

    @Override
    protected void doOKAction() {
        ApiInfo apiInfo = new ApiInfo();
        apiInfo.setApiPath(apiPathField.getText());
        if (StrUtil.isBlank(apiInfo.getApiPath())) {
            JOptionPane.showMessageDialog(null, "接口路径不能为空");
            return;
        }
        apiInfo.setApiDesc(apiDescField.getText());
        List<String> selectedProduct = getSelectedProduct();

        if (CollUtil.isEmpty(selectedProduct)) {
            JOptionPane.showMessageDialog(null, "请选择产品");
            return;
        }

        if (StrUtil.isBlank(authorField.getText())) {
            JOptionPane.showMessageDialog(null, "请填写接口开发者");
            return;
        }

        if (StrUtil.isBlank(apiInfo.getApiDesc())) {
            JOptionPane.showMessageDialog(null, "请填写接口接口描述");
            return;
        }
        KcGatewaySettings settings = KcGatewaySettings.getInstance();
        Map<String, KcProduct> productMap = productList.stream()
                .collect(Collectors.toMap(KcProduct::getName, it -> it, (o, n) -> n));
        for (String productName : selectedProduct) {
            KcProduct kcProduct = productMap.get(productName);
            apiInfo.setProductType(kcProduct.getId());
            KcService kcService = (KcService) serviceComboBox.getSelectedItem();
            if (kcService != null) {
                apiInfo.setServiceName(kcService.getServiceName());
            }
            RouteType routeType = (RouteType) routeTypeComboBox.getSelectedItem();
            if (routeType != null) {
                apiInfo.setRouteType(routeType.getId());
            }
            apiInfo.setAuthor(authorField.getText());

            if (StrUtil.isNotBlank(authorField.getText())) {
                settings.setAuthor(authorField.getText());
            }
            List<Menu> selectedResources = getSelectedResources(productName);

            List<List<String>> resourceIdentifierAllLevels = new ArrayList<>();

            if (CollUtil.isNotEmpty(selectedResources)) {
                apiInfo.setAuthorization(true);
                //保存按钮
                List<String> resourceIdentifier = selectedResources.stream().map(Menu::getId).collect(Collectors.toList());
                apiInfo.setResourceIdentifier(resourceIdentifier);
                for (String resourceId : resourceIdentifier) {
                    List<String> resourceChain = getResourceChain(resourceId, kcProduct.getId());
                    resourceIdentifierAllLevels.add(resourceChain);
                }
            }
            apiInfo.setResourceIdentifierAllLevels(resourceIdentifierAllLevels);
            ApiInfo existApiInfo = getApiInfo(apiInfo.getApiPath(), apiInfo.getServiceName());
            if (existApiInfo != null) {
                apiInfo.setId(existApiInfo.getId());
                RequestApi.editApi(apiInfo);
            } else {
                RequestApi.addApi(apiInfo);
            }
        }
        JOptionPane.showMessageDialog(null, "保存成功");
        this.dispose();

        //刷新
        if (flushCache) {
            RequestApi.flushCache();
        }
    }

    private KcService matchKcServiceByArtifactId(List<KcService> serviceList, String artifactId) {
        for (KcService kcService : serviceList) {
            if (kcService.getServiceUrl().contains(artifactId)) {
                return kcService;
            }

        }
        return null;
    }

    private ApiInfo getApiInfo(String apiPath, String serviceName) {
        ApiInfoPage apiInfoPage = RequestApi.pageApiInfo(apiPath, serviceName);
        List<ApiInfo> rows = apiInfoPage.getRows();
        if (CollUtil.isNotEmpty(rows)) {
            return rows.get(0);
        }
        return null;
    }

    private void createUIComponents() {
        //接口地址回填
        apiPathField = new JTextField();
        serviceComboBox = new JComboBox<>();
        routeTypeComboBox = new JComboBox<>();
        authorField = new JTextField();
        apiDescField = new JTextField();
        resourceTreePanel = new JPanel();
        resourceTreePanel.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));

        productMenu = RequestApi.resourcesList();
        //查询产品列表
        productList = RequestApi.listKcProduct();

        //查询服务列表
        serviceList = RequestApi.listKcService();
        String artifactId = MavenUtil.getArtifactId(actionEvent);
        currentKcService = matchKcServiceByArtifactId(serviceList, artifactId);

        //获取已存在的接口
        String apiPath = ControllerInfoUtil.getApiPath(actionEvent);
        ApiInfoPage apiInfoPage = RequestApi.pageApiInfo(apiPath, currentKcService != null ? currentKcService.getServiceName() : null);
        if (apiInfoPage.getTotal() > 0) {
            apiInfos = apiInfoPage.getRows();
        }

        //查询产品列表
        List<Integer> productIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(apiInfos)) {
            productIds = apiInfos.stream().map(item -> item.getProductType()).collect(Collectors.toList());
        }
        products = new JPanel();

        Map<String, KcProduct> productMap = productList.stream()
                .collect(Collectors.toMap(KcProduct::getName, it -> it, (o, n) -> n));
        for (KcProduct kcProduct : productList) {
            JCheckBox productCheckBox = new JCheckBox(kcProduct.getName(), productIds.contains(kcProduct.getId()));
            productCheckBox.addActionListener(e -> {
                //切换菜单列表
                List<String> selectedProduct = getSelectedProduct();
                List<Integer> selectedProductIds = selectedProduct.stream().map(item -> productMap.get(item).getId()).collect(Collectors.toList());
                resetResourceTreePanel(selectedProductIds, apiPath);
            });
            products.add(productCheckBox);
        }
        resetResourceTreePanel(productIds, apiPath);
    }

    private void resetResourceTreePanel(List<Integer> productIds, String apiPath) {
        resourceTreePanel.removeAll();
        //渲染菜单
        for (Integer productId : productIds) {
            //获取已关联的资源
            List<String> resources = RequestApi.listResourceByApi(productId, apiPath);
            JTree tree = createUIMenuTree(productId, resources);
            if (tree != null) {
                tree.setVisible(true);
                resourceTreePanel.add(tree, BorderLayout.WEST);
            }
        }
        resourceTreePanel.updateUI();
    }

    private JTree createUIMenuTree(Integer productId, List<String> hasResources) {
        JTree tree = new JTree();
        Map<Integer, KcProduct> productMap = productList.stream()
                .collect(Collectors.toMap(KcProduct::getId, it -> it, (o, n) -> n));
        KcProduct kcProduct = productMap.get(productId);
        Menu rootMenu = new Menu();
        rootMenu.setId("0");
        rootMenu.setId(kcProduct.getName());
        rootMenu.setProductId(productId);
        DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode(kcProduct.getName());

        List<Menu> menuList = productMenu.get(productId.toString());
        if (CollUtil.isEmpty(menuList)) {
            return null;
        }
        for (Menu menu : menuList) {
            menu.setProductId(productId);
            if (CollUtil.isNotEmpty(hasResources)) {
                menu.setChecked(hasResources.contains(menu.getId()));
            }
            DefaultMutableTreeNode checkBoxTreeNode = ResourceTreeUtil.treeCheckBoxTreeNode(rootNode, menu, hasResources);
            rootNode.add(checkBoxTreeNode);
        }
        DefaultTreeModel treeModel = new DefaultTreeModel(rootNode);
        tree.setModel(treeModel);
        CheckBoxNodeRenderer renderer = new CheckBoxNodeRenderer();
        tree.setCellRenderer(renderer);

        final CheckBoxNodeEditor editor = new CheckBoxNodeEditor(tree);
        tree.setCellEditor(editor);
        tree.setEditable(true);
        return tree;

    }

    private List<String> getSelectedProduct() {
        List<String> selectedCheckboxes = new ArrayList<>();
        Component[] components = products.getComponents();
        for (Component component : components) {
            // 判断组件是否为JCheckbox
            if (component instanceof JCheckBox) {
                JCheckBox checkBox = (JCheckBox) component;
                // 判断JCheckbox是否被选中
                if (checkBox.isSelected()) {
                    // 执行相应操作，例如获取选中的元素值
                    String selectedValue = checkBox.getText();
                    selectedCheckboxes.add(selectedValue);
                }
            }
        }
        return selectedCheckboxes;
    }

    private List<Menu> getSelectedResources(String productName) {
        List<Menu> selectedCheckboxes = new ArrayList<>();
        Component[] components = resourceTreePanel.getComponents();
        JTree currentTree = null;
        for (Component component : components) {
            // 判断组件是否为JCheckbox
            if (component instanceof JTree) {
                JTree tree = (JTree) component;
                TreeModel model = tree.getModel();
                DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
                Object userObject = root.getUserObject();
                if (userObject.equals(productName)) {
                    currentTree = tree;
                }
            }
        }

        if (currentTree == null) {
            return selectedCheckboxes;
        }
        TreeModel model = currentTree.getModel();
        DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();
        collectSelectedNodes(root.children(), selectedCheckboxes);

        //移除非底层节点
        if (CollUtil.isNotEmpty(selectedCheckboxes)) {
            Map<String, List<Menu>> parentMenuMap = selectedCheckboxes.stream().collect(Collectors.groupingBy(Menu::getParentId));
            Iterator<Menu> iterator = selectedCheckboxes.iterator();
            while (iterator.hasNext()) {
                Menu menu = iterator.next();
                List<Menu> menus = parentMenuMap.get(menu.getId());
                if (CollUtil.isNotEmpty(menus)) {
                    iterator.remove();
                }
            }
        }

        return selectedCheckboxes;
    }


    private void collectSelectedNodes(Enumeration<TreeNode> children, List<Menu> ret) {
        while (children.hasMoreElements()) {
            DefaultMutableTreeNode node = (DefaultMutableTreeNode) children.nextElement();
            if (node.getUserObject() instanceof CheckBoxNodeData) {
                CheckBoxNodeData userObject = (CheckBoxNodeData) node.getUserObject();
                if (userObject.isChecked()) {
                    if (userObject.getNode() instanceof Menu) {
                        Menu menu = (Menu) userObject.getNode();
                        ret.add(menu);
                    }
                }
            }
            if (CollUtil.isNotEmpty(node.children())) {
                collectSelectedNodes(node.children(), ret);
            }
        }
    }

    private List<String> getResourceChain(String currentResourceId, Integer productId) {
        List<Menu> menus = productMenu.get(productId.toString());
        List<String> ret = new ArrayList<>();
        List<Menu> resources = convertToFlatList(menus);
        Map<String, Menu> resourceMap = resources.stream()
                .collect(Collectors.toMap(Menu::getId, it -> it));
        collectResourceChain(resourceMap, currentResourceId, ret);
        return ret;
    }


    private void collectResourceChain(Map<String, Menu> resourceMap, String currentResourceId, List<String> ret) {
        ret.add(currentResourceId);
        Menu currentResource = resourceMap.get(currentResourceId);
        Menu parentResource = resourceMap.get(currentResource.getParentId());
        if (parentResource != null) {
            collectResourceChain(resourceMap, parentResource.getId(), ret);
        }
    }


    public List<Menu> convertToFlatList(List<Menu> nodes) {
        List<Menu> flatList = new ArrayList<>();
        for (Menu node : nodes) {
            flattenNode(node, flatList);
        }
        return flatList;
    }

    private void flattenNode(Menu node, List<Menu> flatList) {
        flatList.add(node);
        if (CollUtil.isEmpty(node.getChildren())) {
            return;
        }
        for (Menu child : node.getChildren()) {
            flattenNode(child, flatList);
        }
    }


    private SaveAndFlushAction saveAndFlushAction;
    private CustomOKAction okAction;
    private CustomDeleteAction customDeleteAction;

    /**
     * 覆盖默认的ok/cancel按钮
     *
     * @return
     */
    @NotNull
    @Override
    protected Action[] createActions() {
        okAction = new CustomOKAction();
        saveAndFlushAction = new SaveAndFlushAction();
        customDeleteAction = new CustomDeleteAction();
        // 设置默认的焦点按钮
        okAction.putValue(DialogWrapper.DEFAULT_ACTION, true);
        return new Action[]{okAction, saveAndFlushAction, customDeleteAction};
    }

    /**
     * 自定义 ok Action
     */
    protected class SaveAndFlushAction extends DialogWrapperAction {

        protected SaveAndFlushAction() {
            super("保存并刷新缓存");
        }

        @Override
        protected void doAction(ActionEvent actionEvent) {
            flushCache = true;
            doOKAction();
            flushCache = false;
        }
    }


    /**
     * 自定义 ok Action
     */
    protected class CustomOKAction extends DialogWrapperAction {

        protected CustomOKAction() {
            super("保存");
        }

        @Override
        protected void doAction(ActionEvent actionEvent) {
            doOKAction();
        }
    }

    /**
     * 自定义 删除 Action
     */
    protected class CustomDeleteAction extends DialogWrapperAction {

        protected CustomDeleteAction() {
            super("删除");
        }

        @Override
        protected void doAction(ActionEvent actionEvent) {
            int choice = JOptionPane.showConfirmDialog(null, "确定要删除" + apiPathField.getText() + "接口吗？" , "确认删除", JOptionPane.YES_NO_OPTION);
            if (choice != JOptionPane.YES_OPTION) {
                return;
            }
            List<String> selectedProduct = getSelectedProduct();
            KcService kcService = (KcService) serviceComboBox.getSelectedItem();
            ApiInfoPage apiInfoPage = RequestApi.pageApiInfo(apiPathField.getText(), kcService.getServiceName());
            List<ApiInfo> rows = apiInfoPage.getRows();
            if (CollUtil.isEmpty(rows)) {
                return;
            }
            Map<String, KcProduct> productMap = productList.stream()
                    .collect(Collectors.toMap(KcProduct::getName, it -> it, (o, n) -> n));
            for (String productName : selectedProduct) {
                KcProduct kcProduct = productMap.get(productName);
                for (ApiInfo row : rows) {
                    if (row.getProductType().equals(kcProduct.getId())) {
                        HashMap<String, Object> params = new HashMap<>();
                        params.put("id", row.getId());
                        params.put("apiPath", row.getApiPath());
                        params.put("productType", row.getProductType());
                        RequestApi.delApi(params);
                    }

                }

            }

            JOptionPane.showMessageDialog(null, "已删除");
            dispose();
        }
    }

}
